﻿//------------------------------------------------------------------------------
/**
* @author : lynn
* created : 2019.1.3
* purpose : 协程封装
*/
//------------------------------------------------------------------------------
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public static partial class CoroutineFuntion
{
    static MonoBehaviour _mono;
    static MonoBehaviour mono
    {
        get
        {
            if (_mono == null)
                _mono = new GameObject("CoroutineFun").AddComponent<EmptyMono>();
            return _mono;
        }
    }
    /// <summary>
    /// 重复执行函数
    /// </summary>
    /// <param name="time"></param>
    /// <param name="times"></param>
    /// <param name="action"></param>
    /// <param name="handle"></param>
    public static void RepeatAction(float time, int times, System.Action action, out CoroutineMono handle, System.Action onEnd = null)
    {
        if (times <= 0)
        {
            handle = null;
            return;
        }
        CoroutineMono mono = AddCoroutMono();
        handle = mono;
        System.Action del = null;
        del = new System.Action(() => {
            action(); times--;
            if (mono == null)
                return;
            if (times <= 0)
            {
                mono.Stop();
                if (onEnd != null) onEnd();
                return;
            }
            mono.DelayAction(time, del);
        });
        mono.DelayAction(time, del);
    }

    public static void RepeatAction<T>(float time, int times, System.Action<T> action, T t, out CoroutineMono handle, System.Action onEnd = null)
    {
        if (times <= 0)
        {
            handle = null;
            return;
        }
        CoroutineMono mono = AddCoroutMono();
        handle = mono;
        System.Action<T> del = null;
        del = new System.Action<T>((a) =>
        {
            action(a); times--;
            if (mono == null)
                return;
            if (times <= 0)
            {
                mono.Stop();
                if (onEnd != null)
                    onEnd();
                return;
            }
            mono.DelayAction<T>(time, del, t);
        });
        mono.DelayAction<T>(time, del, t);
    }

    public static Coroutine DelayAction(IEnumerator action)
    {
        return mono.StartCoroutine(action);
    }
    public static void DelayAction(float time, System.Action action, out Coroutine co)
    {
        co = StartCoroutine(delay(time, action));
    }
    public static Coroutine DelayAction(float time, System.Action action)
    {
        return StartCoroutine(delay(time, action));
    }

    public static Coroutine DelayAction<T>(float time, System.Action<T> action, T param)
    {
        return StartCoroutine(delay(time, action, param));
    }

    public static Coroutine StartCoroutine(IEnumerator action)
    {
        return mono.StartCoroutine(action);
    }

    public static void StopCoroutine(Coroutine coroutine)
    {
        mono.StopCoroutine(coroutine);
    }
    static CoroutineMono AddCoroutMono()
    {
        return mono.gameObject.AddComponent<CoroutineMono>();
    }
    static IEnumerator delay<T>(float time, System.Action<T> a, T param)
    {
        yield return new WaitForSeconds(time);
        if (a != null)
            a.Invoke(param);
    }
    public interface IWaitResult { bool GetResult(); }
    public static IEnumerator delay(System.Func<bool> result, System.Action a)
    {
        yield return new WaitUntil(result);
        a?.Invoke();

    }

    static IEnumerator delay(float time, System.Action a)
    {

        if (time == 0)
            yield return null;
        else
            yield return new WaitForSeconds(time);
        if (a != null)
            a.Invoke();
    }
}

partial class CoroutineFuntion
{
    public class CoroutineMono : MonoBehaviour
    {
        public void Stop()
        {
            StopAllCoroutines();
            GameObject.Destroy(this);
        }
        public void DelayAction(float time, System.Action action)
        {
            StartCoroutine(delay(time, action));
        }
        public void DelayAction<T>(float time, System.Action<T> action, T param)
        {
            StartCoroutine(delay(time, action, param));
        }
        IEnumerator delay<T>(float time, System.Action<T> a, T param)
        {
            yield return new WaitForSeconds(time);
            if (a != null)
                a.Invoke(param);
        }
        IEnumerator delay(float time, System.Action a)
        {
            yield return new WaitForSeconds(time);
            if (a != null)
                a.Invoke();
        }
    }
    public class EmptyMono : MonoBehaviour
    { }
}